package com.common.metric.processor;

import com.common.metric.annotation.MonitorThreadPool;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author: Sunny
 * @date: 2021/2/1
 * @version: v1.0.0
 */
@Slf4j
public class ThreadPoolMonitorProcessor implements MonitorProcessor {

    private static final String EXECUTOR_NAME = "ThreadPoolMonitorSample";

    private final ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);

    private static final Iterable<Tag> TAG = Collections.singletonList(Tag.of("thread.pool.name", EXECUTOR_NAME));

    @Override
    public void process(Object bean, Field field) {
        MonitorThreadPool monitorThreadPool = AnnotatedElementUtils.getMergedAnnotation(field, MonitorThreadPool.class);
        if (monitorThreadPool == null) {
            log.info("添加线程池监控失败, Bean is {}.", bean);
            return;
        }
        ReflectionUtils.makeAccessible(field);
        Object filedValue = ReflectionUtils.getField(field, bean);
        if (filedValue == null) {
            return;
        }
        Object value = AopProxyUtils.getSingletonTarget(filedValue);

        ThreadPoolExecutor executor;
        if (value instanceof ThreadPoolExecutor) {
            executor = (ThreadPoolExecutor)value;
        } else if (value instanceof ThreadPoolTaskExecutor) {
            executor = ((ThreadPoolTaskExecutor) value).getThreadPoolExecutor();
        } else {
            log.error("添加线程池监控失败, 需要 {}, 或者 {}", ThreadPoolExecutor.class.getName(), ThreadPoolTaskExecutor.class.getName());
            return;
        }
        // 添加到Spring的定时线程池
        scheduledExecutorService.submit(() ->{
            collect(executor);
        });
    }

    private void collect(ThreadPoolExecutor task) {
        Metrics.gauge("thread.pool.core.size", TAG, task, ThreadPoolExecutor::getCorePoolSize);
        Metrics.gauge("thread.pool.largest.size", TAG, task, ThreadPoolExecutor::getLargestPoolSize);
        Metrics.gauge("thread.pool.max.size", TAG, task, ThreadPoolExecutor::getMaximumPoolSize);
        Metrics.gauge("thread.pool.active.size", TAG, task, ThreadPoolExecutor::getActiveCount);
        Metrics.gauge("thread.pool.thread.count", TAG, task, ThreadPoolExecutor::getPoolSize);
        Metrics.gauge("thread.pool.queue.size", TAG, task, e -> e.getQueue().size());
    }

}

